package cn.hz.pi.api;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.FloatByReference;
import com.sun.jna.ptr.IntByReference;

import cn.hz.pi.api.inteface.PiApiMethod;
import cn.hz.pi.api.util.DataManager;
import cn.hz.pi.api.util.DateUtil;
import cn.hz.pi.api.util.PIDateUtil;
import cn.hz.pi.api.util.TagValue;



/**
 * PI·API接口方法工具类
 * 
 * @author huazhuo
 *
 */
public class PiApiUtil extends PiApiSetUtil {

	private static final Logger log = LoggerFactory.getLogger(PiApiUtil.class);

	/**
	 * 链接PI数据库
	 * 
	 * @param api
	 * @param server
	 *            PI服务器地址
	 * @return
	 */
	private static boolean connect(PiApiMethod api, String server) {
		if (null == api || null == server || server.length() == 0) {
			log.error("PI连接失败"+server);
			return false;
		}
		// 向PI服务器发送指令
		int serverFlag = api.piut_setservernode(server);
		if (serverFlag == 0) {
			// 判断是否建立连接
			int connect = api.piut_isconnected();
			if (connect == 1) {
			 
				return true;
			}
		}
		log.error("PI连接失败 " + server);
		return false;
	}

	/**
	 * 判断测点是否存在
	 * 
	 * @param server
	 *            服务器标识
	 * @param tag
	 *            测点名称
	 * @return true:存在; false:不存在
	 */
	public static boolean exist(DataManager server, String tag) {
		return null == getId(server, tag) ? false : true;
	}

	/**
	 * 获取测点ID
	 * 
	 * @param server
	 *            服务器标识
	 * @param tag
	 *            测点名称
	 * @return
	 */
	public static Integer getId(DataManager server, String tag) {
		if (null == tag || tag.length() == 0)
			return null;
		
		PiApiMethod api = getApi(server);//获取读取哪个api接口文件
		String ip = getServer(server);//获取pi数据地址
		if (!connect(api, ip)) {
			return null;
		}

		// 若缓存中不存在，则调用API相关方法读取ID，并将结果存入缓存
		IntByReference id = new IntByReference();
		int flag = api.pipt_findpoint(tag, id);
		if (flag == 0) {
			int value = id.getValue();
			return value;
		}

		return null;
	}

	/**
	 * 获取测点快照信息
	 * 
	 * @param server
	 *            服务器标识
	 * @param tag
	 *            测点名称
	 * @return
	 */
	public static TagValue getInfo(DataManager server, String tag) {
		Integer id = getId(server, tag);
		if (null == id) {
			return null;
		}

		PiApiMethod api = getApi(server);

		FloatByReference rval = new FloatByReference();
		IntByReference istat = new IntByReference();
		IntByReference timedate = new IntByReference();
		int flag = api.pisn_getsnapshot(id, rval, istat, timedate);
		if (flag == 0) {
			return new TagValue(id, PIDateUtil.formatTimeFromPI(timedate.getValue()), rval.getValue(),
					istat.getValue());
		}
		log.error("获取测点快照信息失败! PI:{}, Tag:{}", server, tag);

		return null;
	}
	
	//public int pipt_engunitstring(int pointId, Pointer unit, int len);
	
	
	public static String getTagUnit(DataManager server, String tag) {
		Integer id = getId(server, tag);
		if (null == id) {
			return null;
		}

		PiApiMethod api = getApi(server);
		Pointer  p = new Memory(8);
		int flag = api.pipt_engunitstring(id,  p, 8);
		if (flag == 0) {
			byte[] times = p .getByteArray(0, 8);
			StringBuffer buffer = new StringBuffer();
			for (byte b : times) {

				buffer.append((char) b);
			}

			return buffer.toString().trim();
		}
		log.error("获取测点单位失败! PI:{}, Tag:{}", server, tag);

		return null;
	}
	
	

	/**
	 * 根据指定时点，获取测点信息
	 * 
	 * @param server
	 *            服务器标识
	 * @param tag
	 *            测点名称
	 * @param time
	 *            时点(格式:yyyy-MM-dd HH:mm:ss)
	 * @return
	 */
	public static TagValue getInfoByTime(DataManager server, String tag, String time) {
		
		// 若时间为空,则返回测点快照值
		if (null == time || time.length() == 0) {
			return getInfo(server, tag);
		}

		// 测点ID
		Integer id = getId(server, tag);
		if (null == id) {
			return null;
		}

		PiApiMethod api = getApi(server);

		IntByReference timedate = new IntByReference(PIDateUtil.formatTimeToPI(time));
		FloatByReference rval = new FloatByReference();
		IntByReference state = new IntByReference();
		int flag = api.piar_value(id, timedate, 3, rval, state);
		if (0 == flag) {
			return new TagValue(id, PIDateUtil.formatTimeFromPI(timedate.getValue()), rval.getValue(),
					state.getValue());
		}
		log.error("获取测点值失败! PI:{}, Tag:{}, Time:{}", server, tag, time);

		return null;
	}

	/**
	 * 计算指定类型的测点值
	 * 
	 * @param server
	 *            服务器标识
	 * @param tag
	 *            测点名称
	 * @param starttime
	 *            开始时点(格式:yyyy-MM-dd HH:mm:ss)
	 * @param endtime
	 *            结束时点(格式:yyyy-MM-dd HH:mm:ss)
	 * @param caltype
	 *            计算类型(0:和; 1:最小值; 2:最大值; 3:标准差; 4:值域; 5:时间加权平均值; 6:算数平均值)
	 * @return
	 */
	public static TagValue getCalInfo(DataManager server, String tag, String starttime, String endtime, int caltype) {

		// 测点ID
		Integer id = getId(server, tag);
		if (null == id) {
			return null;
		}

		// 开始时间
		IntByReference time1 = new IntByReference();
		time1.setValue(PIDateUtil.formatTimeToPI(starttime));

		// 结束时间
		IntByReference time2 = new IntByReference();
		time2.setValue(PIDateUtil.formatTimeToPI(endtime));

		FloatByReference rval = new FloatByReference();
		

		PiApiMethod api = getApi(server);
		int flag = api.piar_summary(id, time1, time2, rval, new FloatByReference(), caltype);
		if (flag == 0) {
			// 获取最大值或最小值时,需返回时间戳
			if (caltype == 1 || caltype == 2) {
				return new TagValue(id, PIDateUtil.formatTimeFromPI(time1.getValue()), rval.getValue(), 0);
			}

			return new TagValue(id, null, rval.getValue(), 0);
		}
		log.error("测点计算错误! PI:{}, 测点:{}, 时间:{}至{}, 类型:{},  错误码:{}", server, tag, starttime, endtime, caltype, flag);

		return null;
	}

	/**
	 * 根据时间区段,获取测点值列表
	 * 
	 * @param server
	 *            服务器标识
	 * @param tag
	 *            测点名称
	 * @param starttime
	 *            开始时点(格式:yyyy-MM-dd HH:mm:ss)
	 * @param endtime
	 *            结束时点(格式:yyyy-MM-dd HH:mm:ss)
	 * @param count
	 *            预想返回值个数
	 * @return
	 */
	public static List<TagValue> getInfoList(DataManager server, String tag, String starttime, String endtime, int count) {

		// 参数校验

		// 测点ID
		Integer id = getId(server, tag);
		if (null == id) {
			return null;
		}

		if (count < 2) {
			count = 2;
		}

		IntByReference rcount = new IntByReference(count);
		int[] times = new int[count];
		times[0] = PIDateUtil.formatTimeToPI(starttime);
		times[count - 1] = PIDateUtil.formatTimeToPI(endtime);
		float[] rvals = new float[count];
		int[] states = new int[count];

		PiApiMethod api = getApi(server);

		int flag = api.piar_interpvalues(id, rcount, times, rvals, states);
		if (flag == 0) {
			List<TagValue> list = new ArrayList<TagValue>();
			int retCount = rcount.getValue();
			for (int i = 0; i < retCount; i++) {
				list.add(new TagValue(-1, PIDateUtil.formatTimeFromPI(times[i]), rvals[i], states[i]));
			}

			return list;
		}
		log.error("获取测点值列表错误! PI:{}, 测点:{}, 时间:{}至{}, 错误码:{}", server, tag, starttime, endtime, flag);

		return null;
	}

	/**
	 * 
	 * 计算公式值
	 * 
	 * @param server
	 *            服务器标识
	 * @param calcstr
	 *            公式
	 * @param starttime
	 *            开始时点(格式:yyyy-MM-dd HH:mm:ss)
	 * @param endtime
	 *            结束时点(格式:yyyy-MM-dd HH:mm:ss)
	 * @param count
	 *            预想返回值个数
	 * @return
	 */
	public static List<TagValue> getCalCulation(DataManager server, String calcstr, String starttime, String endtime,
			int count) {

		if (null == calcstr || calcstr.length() == 0) {
			return null;
		}

		PiApiMethod api = getApi(server);
		if (!connect(api, getServer(server))) {
			return null;
		}

		if (count < 2) {
			count = 2;
		}

		IntByReference rCount = new IntByReference(count);
		int[] rTimes = new int[count];
		rTimes[0] = PIDateUtil.formatTimeToPI(starttime);
		rTimes[count - 1] = PIDateUtil.formatTimeToPI(endtime);
		float[] rvals = new float[count];
		int[] istats = new int[count];

		int flag = api.piar_calculation(rCount, rTimes, rvals, istats, calcstr);
		if (flag == 0) {
			List<TagValue> list = new ArrayList<TagValue>();
			int retCount = rCount.getValue();
			for (int i = 0; i < retCount; i++) {
				list.add(new TagValue(-1, PIDateUtil.formatTimeFromPI(rTimes[i]), rvals[i], istats[i]));
			}

			return list;
		}
		log.error("计算公式值错误! PI:{}, 公式:{}, 时间:{}至{}, 错误码:{}", server, calcstr, starttime, endtime, flag);
		return null;
	}

	/**
	 * 批量获取测点快照信息
	 * 
	 * @param server
	 *            服务器标识
	 * @param tagMap
	 *            测点名称Map(key:测点名称; value:TagValue)
	 * @return
	 */
	public static Map<String, TagValue> getInfoMap(DataManager server, Map<String, Object> tagMap) {
		// 参数判断
		if (null == tagMap || tagMap.isEmpty()) {
			return null;
		}

		Map<Integer, String> tagIdMap = new HashMap<Integer, String>();

		for (Map.Entry<String, Object> entry : tagMap.entrySet()) {

			String tagname = entry.getKey();
			Integer id = getId(server, tagname);
			if (null == id) {
				continue;
			}

			tagIdMap.put(id, tagname);
		}

		if (null == tagIdMap || tagIdMap.isEmpty()) {
			return null;
		}

		int count = tagIdMap.size();
		int[] pt = new int[count];

		int num = 0;
		for (Map.Entry<Integer, String> entry : tagIdMap.entrySet()) {
			pt[num] = entry.getKey();
			num++;
		}

		float[] rval = new float[count];
		int[] istat = new int[count];
		int[] timedate = new int[count];
		int[] error = new int[count];

		PiApiMethod api = getApi(server);
		if (!connect(api, getServer(server))) {
			return null;
		}

		int flag = api.pisn_getsnapshots(pt, rval, istat, timedate, error, count);
		if (flag == 0) {
			Map<String, TagValue> map = new HashMap<>();

			for (int i = 0; i < count; i++) {

				Integer id = pt[i];// 测点ID
				String name = tagIdMap.get(id);// 测点名称

				TagValue tagValue = new TagValue();
				// 测点值
				if (null != rval && rval.length > i) {
					tagValue.setValue(rval[i]);
				}

				// 时间戳
				if (null != timedate && timedate.length > i) {
					tagValue.setTime(PIDateUtil.formatTimeFromPI(timedate[i]));
				}

				// 测点状态
				if (null != istat && istat.length > i) {
					tagValue.setState(istat[i]);
				}

				map.put(name, tagValue);
			}

			return map;
		}
		log.error("批量获取测点快照信息错误! PI:{}, 错误码:{}", server, flag);

		return null;
	}
	
	
	/**
	 * 批量获取测点快照信息
	 * 
	 * @return
	 */
	public static Map<String, TagValue> getInfoValues(DataManager server,List<String> tagList) {
		// 参数判断
		if (null == tagList || tagList.size() == 0) {
			return null;
		}

		Map<Integer, String> tagIdMap = new HashMap<Integer, String>();

		for (String  str : tagList) {
			String tagname = str;
			Integer id = getId(server, tagname);
			if (null == id) {
				continue;
			}
			tagIdMap.put(id, tagname);
		}

		if (null == tagIdMap || tagIdMap.isEmpty()) {
			return null;
		}

		int count = tagIdMap.size();
		int[] pt = new int[count];

		int num = 0;
		for (Map.Entry<Integer, String> entry : tagIdMap.entrySet()) {
			pt[num] = entry.getKey();
			num++;
		}

		float[] rval = new float[count];
		int[] istat = new int[count];
		int[] timedate = new int[count];
		int[] error = new int[count];

		PiApiMethod api = getApi(server);
		if (!connect(api, getServer(server))) {
			return null;
		}

		int flag = api.pisn_getsnapshots(pt, rval, istat, timedate, error, count);
		if (flag == 0) {
			Map<String, TagValue> map = new HashMap<>();
			for (int i = 0; i < count; i++) {

				Integer id = pt[i];// 测点ID
				String name = tagIdMap.get(id);// 测点名称

				TagValue tagValue = new TagValue();
				// 测点值
				if (null != rval && rval.length > i) {
					tagValue.setValue(rval[i]);
				}

				// 时间戳
				if (null != timedate && timedate.length > i) {
					tagValue.setTime(PIDateUtil.formatTimeFromPI(timedate[i]));
				}

				// 测点状态
				if (null != istat && istat.length > i) {
					tagValue.setState(istat[i]);
				}

				map.put(name, tagValue);
			}

			return map;
		}
		log.error("批量获取测点快照信息错误! PI:{}, 错误码:{}", server, flag);

		return null;
	}
	
	
	/**
	 * 批量获取测点快照信息
	 * 
	 * @return
	 */
	public static float[] getInfoValuesnew(DataManager server,List<String> tagList) {
		// 参数判断
		if (null == tagList || tagList.size() == 0) {
			return null;
		}

		Map<Integer, String> tagIdMap = new HashMap<Integer, String>();

		for (String  str : tagList) {
			String tagname = str;
			Integer id = getId(server, tagname);
			if (null == id) {
				continue;
			}
			tagIdMap.put(id, tagname);
		}

		if (null == tagIdMap || tagIdMap.isEmpty()) {
			return null;
		}

		int count = tagIdMap.size();
		int[] pt = new int[count];

		int num = 0;
		for (Map.Entry<Integer, String> entry : tagIdMap.entrySet()) {
			pt[num] = entry.getKey();
			num++;
		}

		float[] rval = new float[count];
		int[] istat = new int[count];
		int[] timedate = new int[count];
		int[] error = new int[count];

		PiApiMethod api = getApi(server);
		if (!connect(api, getServer(server))) {
			return null;
		}

		int flag = api.pisn_getsnapshots(pt, rval, istat, timedate, error, count);
		if (flag == 0) {
			return	rval;
			}


		return null;
	}
	

	/**
	 * 保存测点快照值
	 * 
	 * @param server
	 *            服务器标识
	 * @param tag
	 *            测点信息
	 * @return
	 */
	public static boolean putSnapshot(DataManager server, TagValue tag) {

		// 参数检验
		if (null == tag)
			return false;

		Float value = tag.getValue();
		if (null == value) {
			return false;
		}

		// 获取测点ID
		String name = tag.getName();
		Integer id = getId(server, name);
		if (null == id) {
			return false;
		}

		PiApiMethod api = getApi(server);

		// PI时间转化
		Integer timedate = PIDateUtil.formatTimeToPI(tag.getTime());
		if (null == timedate) {
			timedate = 0;
		}

		// 保存测点快照值
		int flag = api.pisn_putsnapshot(id, value, 0, timedate);
		if (flag == 0) {
			return true;
		}
		log.error("保存测点快照值错误! PI:{}, Tag:{}, 错误码:{}", server, name, flag);

		return false;
	}

	/**
	 * 批量保存测点快照值
	 * 
	 * @param server
	 *            服务器标识
	 * @param tagMap
	 *            测点信息Map
	 * @return
	 */
	public static boolean putSnapshots(DataManager server, Map<String, TagValue> tagMap) {

		// 参数检验
		if (null == tagMap || tagMap.isEmpty()) {
			return false;
		}

		List<TagValue> list = new ArrayList<>();

		// 获取测点ID
		for (Map.Entry<String, TagValue> entry : tagMap.entrySet()) {

			TagValue tagValue = entry.getValue();
			if (null == tagValue || null == tagValue.getValue()) {
				continue;
			}

			String name = entry.getKey();
			Integer id = getId(server, name);// 测点ID
			if (null == id) {
				continue;
			}

			tagValue.setId(id);
			list.add(tagValue);
		}

		int count = list.size();
		if (count == 0) {
			return false;
		}

		int[] pt = new int[count];
		float[] rval = new float[count];
		int[] istat = new int[count];
		int[] timedate = new int[count];

		for (int i = 0; i < count; i++) {

			TagValue tagValue = list.get(i);

			pt[i] = tagValue.getId();
			rval[i] = tagValue.getValue();
			istat[i] = 0;

			// PI时间转化
			Integer time = PIDateUtil.formatTimeToPI(tagValue.getTime());
			if (null == time) {
				time = 0;
			}
			timedate[i] = time;
		}

		PiApiMethod api = getApi(server);
		int flag = api.pisn_putsnapshots(pt, rval, istat, timedate, new IntByReference[count], count);
		if (flag == 0) {
			return true;
		}
		log.error("批量保存测点快照值错误! PI:{}, 错误码:{}", server, flag);

		return false;
	}

	public static boolean connect(DataManager db) {
		return connect(getApi(db), getServer(db));
	}

	/**
	 * 获取测点趋势信息
	 * 
	 * @param server
	 *            数据源名称
	 * @param tag
	 *            测点名称
	 * @param starttime
	 *            开始时点(格式:yyyy-MM-dd hh:mm:ss)
	 * @param endtime
	 *            结束时点(格式:yyyy-MM-dd hh:mm:ss)
	 * @param count
	 *            返回值个数
	 * @return
	 */
	public static List<TagValue> getValueList(DataManager server, String tag, String starttime, String endtime, int count) {
		PiApiMethod api = getApi(server);
		if (null == api) {
			return null;
		}

		long seconds = DateUtil.secondBetween(starttime, endtime);
		if (seconds < 1) {
			return null;
		}

		Integer id = getId(server, tag);
		if (null == id) {
			return null;
		}

		if (seconds < count) {
			count = (int) seconds;
		}

		IntByReference rcount = new IntByReference();
		rcount.setValue(count);
		int[] times = new int[count];
		times[0] = PIDateUtil.formatTimeToPI(starttime);
		times[count - 1] = PIDateUtil.formatTimeToPI(endtime);
		float[] rvals = new float[count];
		int[] states = new int[count];

		int flag = api.piar_interpvalues(id, rcount, times, rvals, states);
		if (0 == flag) {
			List<TagValue> list = new ArrayList<>();
			for (int i = 0; i < count; i++) {
				list.add(new TagValue(id, PIDateUtil.formatTimeFromPI(times[i]), rvals[i], states[i]));
			}
			return list;
		}
		return null;
	}
	
	public static String pipt_digstate(DataManager server,int statusId) {
		PiApiMethod api = getApi(server);
		Pointer  p = new Memory(8);
		int flag= api.pipt_digstate(statusId,p,8);
		 if (flag == 0) {
				byte[] times = p .getByteArray(0, 8);
				StringBuffer buffer = new StringBuffer();
				for (byte b : times) {

					buffer.append((char) b);
				}

				return buffer.toString().trim();
			}
		 return null;
	}
	
	
	
	
	public static void main(String[] args) {
		
		
	//TagValue tagv = PiApiUtil.getInfo(null,"ELE.channel:0.YM.YM5");
	
		DataManager mg= new DataManager();
		//mg.setPiService("192.168.0.109");
//	//	TagValue tagb = PiApiUtil.getCalInfo(mg, "TEST2", "2020-04-03 10:00:00", "2020-04-03 10:12:00", 2);
//	String curve = "curve('cdt158',(100,30)(250,100))";
//	List<TagValue> list = PiApiUtil.getCalCulation(mg, curve, "2020-05-21 10:00:00", "2020-05-21 17:00:00", 50);
//	for (TagValue tagValue : list) {
//		System.out.println(tagValue);
//	}
//	 
//	    mg.setPiService("192.168.0.109");
//	  // tagb = PiApiUtil.getInfoByTime(mg,"TEST2","2020-03-25 14:00:00");
//	 //  System.out.println(tagb);
//	}
		//OCS1.D.10HFV21CZ001XB02
		
		//DCS1.A.10HAH52CT020XQ01
	System.out.println(PiApiUtil.getInfoByTime(null, "DCS2.D.20HFC50CZ001XB01","2020-06-10 08:52:24"))	;
	
	System.out.println(PiApiUtil.pipt_digstate(null,-524288));
//		List<TagValue> list = PiApiUtil.getInfoList(mg, "TESTDG3", "2020-05-25 09:34:00", "2020-03-25 09:35:00", 10);
//		for (TagValue tagValue : list) {
//			System.out.println(tagValue);
//		}
//		/* pipt_digstate */
		
	}

}
